package com.qdlc.p2p.biz.service.impl;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.qd.p2p.adapter.Response;
import com.qd.p2p.adapter.enums.ResponseStatus;
import com.qd.p2p.sina.pay.enums.IdentityType;
import com.qdlc.p2p.biz.processor.event.RepayUpRatePayNoticeEvent;
import com.qdlc.p2p.biz.processor.event.TppDispatchValueEvent;
import com.qdlc.p2p.biz.service.AbstractPayService;
import com.qdlc.p2p.biz.service.AccountService;
import com.qdlc.p2p.biz.service.RPCRequestService;
import com.qdlc.p2p.biz.service.RateInterestService;
import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.constant.LogTplNid;
import com.qdlc.p2p.common.constant.NotifyUrl;
import com.qdlc.p2p.common.constant.SinaConstant;
import com.qdlc.p2p.common.constant.Summary;
import com.qdlc.p2p.common.constant.TradeCode;
import com.qdlc.p2p.common.constant.TradeStatus;
import com.qdlc.p2p.common.constant.UpRateCollectionStatus;
import com.qdlc.p2p.common.core.ReturnResult;
import com.qdlc.p2p.common.core.queue.QueueHandlers;
import com.qdlc.p2p.common.exception.BusinessException;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.DataUtils;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.common.SystemConfigHelper.Nid;
import com.qdlc.p2p.dal.dao.BorrowCollectionDao;
import com.qdlc.p2p.dal.dao.BorrowDao;
import com.qdlc.p2p.dal.dao.BorrowRepaymentDao;
import com.qdlc.p2p.dal.dao.TppDao;
import com.qdlc.p2p.dal.dao.UpRateCollectionDao;
import com.qdlc.p2p.dal.dto.Borrow;
import com.qdlc.p2p.dal.dto.BorrowCollection;
import com.qdlc.p2p.dal.dto.BorrowRepayment;
import com.qdlc.p2p.dal.dto.Tpp;
import com.qdlc.p2p.dal.dto.TppTradeLog;
import com.qdlc.p2p.dal.dto.UpRateCollection;
import com.qdlc.p2p.dal.model.TppModel;
import com.qdlc.p2p.dal.model.TppTradeLogModel;
import com.qdlc.p2p.dal.util.UserUtils;

@Service("borrowRepayUpRatePayService")
public class BorrowRepayUpRatePayServiceImpl extends AbstractPayService {

    private final static String BUSINESS_NAME = "还款加息代付-";

    /** 代收交易Log */
    private ThreadLocal<TppTradeLog> collectTppTradeLogLocal = new ThreadLocal<TppTradeLog>();

    @Resource
    private BorrowDao borrowDao;

    @Resource
    private BorrowRepaymentDao borrowRepaymentDao;

    @Resource
    private UpRateCollectionDao upRateCollectionDao;

    @Resource
    private RateInterestService rateInterestService;

    @Resource
    private BorrowCollectionDao borrowCollectionDao;

    @Resource
    private TppDao tppDao;

	@Resource
	private AccountService accountService;

    @Resource
    @Qualifier("bfRPCRequestService")
    private RPCRequestService<Response, TppTradeLog> rpcRequestService;

    @Override
    public void analyzePars(Object... pars) {
        if (pars.length != 1) {
            throw new IllegalArgumentException("参数个数正确!");
        }
        try {
            TppTradeLog collectTppTradeLog = (TppTradeLog) pars[0]; // 代收交易Log
            if (collectTppTradeLog == null) {
                throw new IllegalArgumentException("参数类型正确!");
            }
            collectTppTradeLogLocal.set(collectTppTradeLog);
        } catch (Exception ex) {
            throw new IllegalArgumentException("参数类型正确!");
        }
    }

    @Override
    public boolean preCreateOrder() {
        BorrowCollection borrowCollection = (BorrowCollection) Global.getTransfer().get("borrowCollection");
        if (borrowCollection == null) {
            Map<String, Object> memo = DataUtils.getMemo(collectTppTradeLogLocal.get().getMemo());
            long collectionId = DataUtils.toLong(memo.get("collectionId")); // 还款记录ID
            borrowCollection = borrowCollectionDao.find(collectionId);
        }
        UpRateCollection upRateCollection = upRateCollectionDao.getUpRateCollectionByCId(borrowCollection.getId());
        // 没有用加息券
        if (upRateCollection == null) {
            return false;

            // 加息券已用
        } else if (upRateCollection.getStatus() == UpRateCollectionStatus.ALREADY_REPAYMENT) {
            logger.info("该加息已还款!");
            return false;
        }
        return true;
    }

    @Override
    public TppTradeLog getTppTradeLog() {
        TppTradeLog collectTppTradeLog = collectTppTradeLogLocal.get();

        BorrowRepayment borrowRepayment = (BorrowRepayment) Global.getTransfer().get("borrowRepayment");
        BorrowCollection borrowCollection = (BorrowCollection) Global.getTransfer().get("borrowCollection");
        Map<String, Object> memo = DataUtils.getMemo(collectTppTradeLog.getMemo());
        memo.put("collectionId", borrowCollection.getId());
        memo.put("userId", borrowCollection.getUser().getUserId());

        // 加息 利息
        double repayAmount = rateInterestService.getUpRateInterestByCollectionId(borrowCollection.getId());
        // 收款用户 第三方TPP_ID
        String userTppId = UserUtils.getUserTppCustId(borrowCollection.getUser().getUserId());

        // 创建代付订单
        TppTradeLog tppTradeLog = new TppTradeLog();
        tppTradeLog.setTppUserCustId(SystemConfigHelper.getSystemConfig(Nid.MERCHANT_ID).getValue()); // 平台支付
        tppTradeLog.setIdentityType(IdentityType.EMAIL.name());
        tppTradeLog.setToTppUserCustId(userTppId); // 投资人custId
        tppTradeLog.setMoney(repayAmount);  // 还款 加息金额
        tppTradeLog.setBorrowId(collectTppTradeLog.getBorrowId()); // 标ID
        tppTradeLog.setBorrowRepaymentId(borrowRepayment.getId()); // 还款ID
        tppTradeLog.setMemo((new Gson()).toJson(memo));
        tppTradeLog.setAssociateOrderId(collectTppTradeLog.getOrderNo()); // 关联代收订单
        tppTradeLog.setTradeType(TradeCode.C2005.toString());
        tppTradeLog.setServiceType(Summary.REPAY.getSummaryType()); // 还款
        return tppTradeLog;
    }

    @Override
    public List<TppTradeLog> createOrders(Object... pars) {
        analyzePars(pars);
        TppTradeLog collectTppTradeLog = collectTppTradeLogLocal.get();
        BorrowRepayment borrowRepayment = borrowRepaymentDao.find(collectTppTradeLog.getBorrowRepaymentId());

        // 应还金额累积
        double repayTotalAmount = 0;

        // 代付订单
        List<TppTradeLog> tppTradeLogs = Lists.newArrayList();
        // 生成代付订单
        List<BorrowCollection> borrowCollectionList = borrowCollectionDao.list(collectTppTradeLog.getBorrowId(), borrowRepayment.getPeriod());
        for (BorrowCollection borrowCollection : borrowCollectionList) {
            Global.setTransfer("borrowRepayment", borrowRepayment);
            Global.setTransfer("borrowCollection", borrowCollection);
            TppTradeLog newTppTradeLog = super.createOrder(pars);
            if (newTppTradeLog != null) {
                tppTradeLogs.add(newTppTradeLog);
                // 应还金额累积
                repayTotalAmount = BigDecimalUtil.add(repayTotalAmount, newTppTradeLog.getMoney());
            }
        }

        // 代收的加息金额 与 应还的加息金额不一致 说明程序有bug
        BigDecimal repayTotalAmountDecimal = new BigDecimal(repayTotalAmount);
        BigDecimal moneyDecimal = new BigDecimal(collectTppTradeLog.getMoney());
        if (repayTotalAmountDecimal.compareTo(moneyDecimal) != 0) {
            throw new BusinessException(MessageFormat.format("第{0}期 还款代收本息金额 与 还款代付本息金额不一致,无法完成代付! 代收本息金额:{1} 代付本息金额:{2}",
                    borrowRepayment.getPeriod(), collectTppTradeLog.getMoney(), repayTotalAmount));
        }
        return tppTradeLogs;
    }

    @Override
    public ReturnResult requestOrder(TppTradeLog tppTradeLog) {
        Response response = rpcRequestService.repayUpRatePayRequest(tppTradeLog);
        // 未知状态通知 交由消息队列处理
        if (response == null || response.getStatus() == ResponseStatus.UN_KNOW) {
            notice(tppTradeLog, TradeStatus.TRADE_STATUS_UN_KNOW);
            return new ReturnResult(true, "系统处理中!请查看投标结果!");
        }
        // 代付调用成功
        if (response.getStatus() == ResponseStatus.SUCCESS) {
            tppTradeLog.setRemark(getBusinessName().concat("提交成功"));
            tppTradeService.update(tppTradeLog);

            // 成功通知
            notice(tppTradeLog, TradeStatus.TRADE_STATUS_FINISHED);
            requestOrderSuccess(tppTradeLog); // 请求成功处理
            // 失败
        } else if (response.getStatus() == ResponseStatus.FAILURE) {
            String message = response == null ? "RPC调用失败" : MessageFormat.format("代付失败!resCode:{0} resMessage:{1}",
                     response.getResponseCode(),
                    response.getResponseMsg());
            String responseMessage = response == null ? "RPC调用失败" : response.getResponseMsg();
            logger.info(message);

            // 置为废单
            tppTradeLog.setTradeStatus(TradeStatus.TRADE_STATUS_INVALID.getStatus());
            tppTradeLog.setRemark(getBusinessName().concat("提交失败-" + responseMessage));
            tppTradeService.update(tppTradeLog);
            requestOrderFail(tppTradeLog); // 请求失败处理
            return new ReturnResult(true, message);
        }
        return ReturnResult.SUCCESS;
    }

    @Override
    public void requestOrderFail(TppTradeLog tppTradeLog) {
        // 保存调度任务信息
        Tpp tpp = new Tpp();
        tpp.setStatus(TppModel.STATUS_FAIL);
        tpp.setServiceType(TppModel.DOREPAY);
        tpp.setTppType(SinaConstant.TRADE_SERVICE_REPAY);
        tpp.setTppUserCustId(tppTradeLog.getTppUserCustId());// 借款人托管账户ID
        tpp.setMoney(tppTradeLog.getMoney());
        tpp.setOrderId(tppTradeLog.getOrderNo());
        tpp.setOrderDate(DateUtil.dateStr7(tppTradeLog.getAddTime()));
        tpp.setExtended(tppTradeLog.getBorrowRepaymentId() + "");// 还款ID
        tpp.setTradeType(tppTradeLog.getTradeType());
        tpp.setRespDesc(tppTradeLog.getRemark());
        tpp.setAddTime(DateUtil.getNow());
        tpp.setTppBorrowId(tppTradeLog.getBorrowId() + "");// 标ID
        tppDao.save(tpp);
        
        // 调度任务交由队列处理(延时处理)
        if (tppTradeLog.getAutoDispatch() != TppTradeLogModel.IS_AUTO) {// 防止重复处理
        	TppModel tppModel = TppModel.instance(tpp);
        	TppDispatchValueEvent tppDispatchValueEvent = new TppDispatchValueEvent();
        	tppDispatchValueEvent.setTppModel(tppModel);
            QueueHandlers.put(tppDispatchValueEvent);
        }
    }

    @Override
    public void tradeFinish(TppTradeLog tppTradeLog, String depositStatus, double tradeAmount) {
        super.tradeFinishForStatus(tppTradeLog, depositStatus, tradeAmount);

        // logMemo
        Map<String, Object> memo = DataUtils.getMemo(tppTradeLog.getMemo());

        long userId = DataUtils.toLong(memo.get("userId")); // 用户ID
        long collectionId = DataUtils.toLong(memo.get("collectionId")); // 还款记录ID

        // 获得使用加息券后，对应每个collection产生的额外利息
        UpRateCollection upCollection = upRateCollectionDao.getUpRateCollectionByCId(collectionId);
        double upInterest = upCollection.getDifferenceInterest();  // 加息收益

        // 更新加息券额外收益还款状态
        upCollection.setStatus(UpRateCollectionStatus.ALREADY_REPAYMENT);
        upCollection.setRepaymentYesTime(DateUtil.getNow());
        upCollection.setWebPayMoney(upInterest);
        upRateCollectionDao.update(upCollection);

        Borrow borrow = borrowDao.find(upCollection.getBorrowId());

        // 加息 资金变更
        Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.RATE_REPAY_INTEREST);
        Global.setTransfer("web_url", WEB_URL);
        Global.setTransfer("borrow", borrow);
        Global.setTransfer("money", upInterest);
		accountService.revokeCapital(userId, userId, upInterest);
    }

    @Override
    public void tradeSuccess(TppTradeLog tppTradeLog, String depositStatus) {
        super.tradeSuccessForStatus(tppTradeLog, depositStatus);
    }

    @Override
    public void tradeFail(TppTradeLog tppTradeLog, String depositStatus) {
        super.tradeFailForStatus(tppTradeLog, depositStatus);
    }

    @Override
    public String getCallBackUrl() {
        return WEB_URL.concat(NotifyUrl.REPAY_NOTIFY_UP_RATE_PAY_URL).concat(".html");

    }

    @Override
    public String getBusinessName() {
        return BUSINESS_NAME;
    }

    /**
     * 发送投标通知 交由队列来执行
     */
    private void notice(TppTradeLog tppTradeLog, TradeStatus tradeStatus) {
        RepayUpRatePayNoticeEvent event = new RepayUpRatePayNoticeEvent();
        event.setClientIp(Global.getIP());
        event.setTradeStatus(tradeStatus);
        event.setTppTradeLog(tppTradeLog);
        event.setOutOrderNo(tppTradeLog.getOrderNo());
        event.setDepositAmount(tppTradeLog.getMoney());
        QueueHandlers.put(event);
    }
}